package com.xyy.saas.payment.util;

import com.xyy.framework.redis.core.RedisClient;
import com.xyy.framework.redis.util.FastJsonUtil;
import lombok.extern.log4j.Log4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Log4j
@Component
public class RedisUtil {
    // 一秒
    public static final Integer SECOND = 1;
    // 五秒
    public static final Integer SECOND_5 = SECOND * 5;
    // 一分钟
    public static final Integer MINUTE = SECOND * 60;
    // 十分钟
    public static final Integer MINUTE_10 = MINUTE * 10;
    // 三十分钟
    public static final Integer MINUTE_30 = MINUTE * 30;

    @Autowired
    private RedisClient redisClient;
    @Autowired
    StringRedisTemplate redisTemplate;
    @Resource(name = "xyyRedisTemplate")
    private RedisTemplate xyyRedisTemplate;

    /**
     * 默认值
     */
    public static String DEFAULT_VALUE = "default_value";
    /**
     * 结算前缀
     */
    public static String PREFIX_PROFIT_SHARING = "prefix_profit_sharing_";
    /**
     * 京东授信准入结果通知
     */
    public static String JD_CREDIT_RESULT_NOTIFY = "jd_credit_result_notify";

    /**
     * 小雨点授信准入结果通知
     */
    public static String XYD_RESULT_NOTIFY = "xyd_result_notify";

    /**
     * 京东退款结果通知
     */
    public static String JD_CREDIT_REFUND_NOTIFY = "jd_credit_refund_notify";

    /**
     * 京东授信结果通知
     */
    public static String JD_CREDIT_PAY_NOTIFY = "jd_credit_pay_notify";

    /**
     * 京东还款结果通知
     */
    public static String JD_CREDIT_REPAY_NOTIFY = "jd_credit_repay_notify";

    /**
     * 农行e贷结果通知
     */
    public static String AB_CHINA_PAY_NOTIFY = "ab_china_pay_notify";

    /**
     * 小雨点支付结果通知
     */
    public static String XYD_LOAN_PAY_NOTIFY = "xyd_loan_pay_notify_";

    public static String XYD_LOAN_REFUND_NOTIFY = "xyd_loan_refund_notify_";

    /**
     * 平安信用支付结算前缀
     */
    public static String PREFIX_PINGAN_CREDIT_PAY_SETTLE = "prefix_pingan_credit_pay_settle_";

    public static String PREFIX_PINGAN_CREDIT_PAY_SETTLE_SUCCESS = "prefix_pingan_credit_pay_settle_success_";

    /**
     * 小雨点支付结算成功标识
     */
    public static String PREFIX_XYD_CREDIT_PAY_SETTLE_SUCCESS = "prefix_xyd_credit_pay_settle_success_";

    /**
     * 小雨点退款结算成功标识
     */
    public static String PREFIX_XYD_CREDIT_REFUND_SETTLE_SUCCESS = "prefix_xyd_credit_refund_settle_success_";

    /**
     * 小雨点支付结算锁
     */
    public static String PREFIX_XYD_CREDIT_PAYER_ACCOUNT_SETTLE_LOCK = "prefix_xyd_credit_payer_account_settle_lock_";

    /**
     * 退款结算锁
     */
    public static String PREFIX_XYD_CREDIT_REFUND_SETTLE_LOCK = "prefix_xyd_credit_refund_settle_lock_";

    /**
     * 小雨点退款lock
     */
    public static String PREFIX_XYD_CREDIT_REFUND_LOCK = "prefix_xyd_credit_refund_lock_";

    /**
     * 小雨点支付分润lock
     */
    public static final String PREFIX_XYD_CREDIT_PAY_PROFITSHARING_LOCK = "prefix_xyd_credit_pay_profitsharing_lock_";

    /**
     * 出金锁
     */
    public static String D_AMOUNT_LOCK = "d_amount_lock_";
    /**
     * 退款前缀
     */
    public static String PREFIX_REFUND = "prefix_refund_";
    /**
     * 退款前缀
     */
    public static String PREFIX_PINGAN_CREDIT_PAY_REFUND = "prefix_pingan_credit_pay_refund_";
    /**
     * 账户修改前缀
     */
    public static String MODIFY_ACCOUNT_PREFIX = "modify_account_prefix_";
    /**
     * 账户修改前缀
     */
    public static String APPLY_BANKCARD_PREFIX = "apply_bankcard_prefix_";

    /**
     * 京东支付前缀
     */
    public static String JD_PAY_PREFIX = "jd_pay_";

    /**
     * 支付回调前缀
     */
    public static String PAY_RESULT_PREFIX = "pay:result:proc:";

    /**
     * 购物金充值
     */
    public static String VIRTUAL_GOLD_TRANSFER_PREFIX = "virtual_gold_transfer_proc_";

    public static String NOTIFY_OFFLINE_REFUND_PREFIX = "notify_offline_refund_";


    public static final String HOLIDAY_REFRESH_CACHE_LOCK = "holiday_refresh_cache_lock";

    public static final String HOLIDAY_CACHE_KEY = "holiday_cache_data";

    public static final String INTERCEPTED_REFUND_ORDERS = "intercepted_refund_orders_key";
    public static final long INTERCEPTED_REFUND_ORDERS_EXPIRE = 60;

    public static String getVirtualGoldTransferPrefix(String businessUserId) {
        return VIRTUAL_GOLD_TRANSFER_PREFIX + businessUserId;
    }

    /**
     * 验证用户是否存在同时申请的redisKey
     */
    public static String getPayResultPrefix(String payNo) {
        return PAY_RESULT_PREFIX + payNo;
    }

    /**
     * 验证用户是否存在同时申请的redisKey
     */
    public static String getJDContractProc(String merchantNo, String bindAccount) {
        return JD_PAY_PREFIX + "proc_" + merchantNo + "_" + bindAccount;
    }

    private String cacheKeyPrefix = "";

    /**
     * 加锁
     *
     * @param key
     * @param value
     * @return
     */
    public boolean setNx(String key, Object value) {
        return redisClient.setNx(key, value);
    }

    /**
     * @param key
     * @param value
     * @param timeOut 单位秒(s)
     * @return
     */
    public boolean setNx(String key, String value, long timeOut) {
        try {
            String result = redisClient.set(key, value, "NX", "EX", timeOut);
            if (StringUtils.isNotBlank(result) && "ok".equalsIgnoreCase(result)) {
                return true;
            }

        } catch (Exception e) {
            log.error("setNx exception", e);
        }
        return false;
    }

    /**
     * @param key
     * @return
     */
    public boolean setNx(String key) {
        return setNx(key, DEFAULT_VALUE);
    }

    /**
     * 获取
     */
    public String get(String key) {
        return redisClient.get(key);
    }

    /**
     * 获取
     */
    public <T> T get(String key, Class<T> clazz) {
        return redisClient.get(key, clazz);
    }

    /**
     * 删除
     */
    public boolean del(String key) {
        if (StringUtils.isBlank(key)) {
            return false;
        }

        return redisClient.del(key);
    }

    /**
     * incr
     */
    public long incr(String category, String key) {
        return redisClient.incr(category, key);
    }

    /**
     * 是否存在
     */
    public boolean exists(String key) {
        return redisClient.exists(key);
    }

    /**
     * 设置
     */
    public boolean set(String key, Object value, int expireSeconds) {
        return redisClient.set(key, value, expireSeconds);
    }

    /**
     * 设置
     */
    public boolean set(String key, long expireSeconds) {
        return redisClient.set(key, DEFAULT_VALUE, expireSeconds);
    }

    /**
     * 尝试是否可以获取到锁：获取到锁，则返回lockKey，否则返回空
     * 此方法仍然存在风险，解决方案
     * 1、升级redis为2.1.0以上，setIfAbsent(lockKey, value, time, TimeUnit.SECONDS)
     * 2、引入redission，使用redission实现分布式锁
     *
     * @param lockKey : key
     * @param value   : value
     * @param time    : 过期时间
     */
    public boolean tryLock(String lockKey, String value, long time) {
        if (StringUtils.isBlank(lockKey)) {
            return false;
        }
        Boolean ifAbsent = redisTemplate.opsForValue().setIfAbsent(lockKey, value);
        if (ifAbsent) {
            redisTemplate.expire(lockKey, time, TimeUnit.SECONDS);
        }
        return ifAbsent;
    }

    public boolean tryLock(String lockKey) {
        return tryLock(lockKey, DEFAULT_VALUE, MINUTE);
    }

    public boolean tryLock(String lockKey, long time) {
        return tryLock(lockKey, DEFAULT_VALUE, time);
    }

    /**
     * 解锁
     *
     * @param lockKey : key
     * @return
     */
    public boolean unLock(String lockKey) {
        if (StringUtils.isNotBlank(lockKey)) {
            return redisTemplate.delete(lockKey);
        }
        return false;
    }

    public <T> void set2(String key, T object) {
        try {
            if (null == key || null == object) {
                return;
            }
            key = cacheKeyPrefix + key;
            String jsonStr = FastJsonUtil.serialize(object);
            xyyRedisTemplate.opsForValue().set(key, jsonStr);
        } catch (Throwable e) {
            log.error("RedisClient [set<T>] error:key=" + key, e);
        }
    }

    public Long sCard(String key) {
        try {
            return redisTemplate.opsForSet().size(key);
        } catch (Exception e) {
            log.error("RedisClient sSize error. key=" + key, e);
            return null;
        }
    }

    public void sAdd(String key, String value) {
        try {
            redisTemplate.opsForSet().add(key, value);
        } catch (Exception e) {
            log.error("RedisClient sAdd error. key=" + key, e);
        }
    }

    public boolean sRem(String key, String value) {
        Long removed = redisTemplate.opsForSet().remove(key, value);
        return removed != null && removed > 0;
    }

    public Set<String> sMembers(String key) {
        return redisTemplate.opsForSet().members(key);
    }

    public Boolean expire(String key, long timeout, TimeUnit unit) {
        return redisTemplate.expire(key, timeout, unit);
    }

    public boolean sIsmember(String key, String value) {
        return Boolean.TRUE.equals(redisTemplate.opsForSet().isMember(key, value));
    }

}
